package com.zhuzhe.blog.advice.handler;

import com.zhuzhe.blog.advice.BusinessException;
import com.zhuzhe.blog.base.JsonData;
import com.zhuzhe.blog.base.ResponseData;
import com.zhuzhe.blog.enums.ResponseEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;


/**
 * @description 全局异常处理: 使用 @RestControllerAdvice + @ExceptionHandler 注解方式实现全局异常处理
 * @author: u53
 * @create: 2020-10-21 14:50
 **/
@RestControllerAdvice
public class GlobalExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler({Exception.class})
    public ResponseData globalExceptionHandler(Exception e) {
        this.logger.error(e.getMessage(), e);
        return JsonData.fail(ResponseEnum.SYSTEM_RUNNING_ERROR);
    }

    @ExceptionHandler(value = DuplicateKeyException.class)
    public ResponseData handleDuplicateKeyException(Exception e) {
        logger.error("该数据已存在：" + e.getMessage());
        return JsonData.fail(ResponseEnum.PRIMARY_CLASH_OR_GROUP_UNIQUE);
    }

    //处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常，详情继续往下看代码
    @ExceptionHandler(BindException.class)
    public ResponseData BindExceptionHandler(BindException e) {
        this.logger.error(e.getMessage(), e);
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        return JsonData.fail(ResponseEnum.PARAM_FAIL.getCode(), message);
    }

    //处理请求参数格式错误 @RequestParam的异常
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseData missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        this.logger.error(e.getMessage(), e);
        return JsonData.fail(ResponseEnum.PARAM_FAIL.getCode(), e.getParameterName() + ResponseEnum.PARAM_FAIL.getMsg());
    }

    //处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseData constraintViolationExceptionHandler(ConstraintViolationException e) {
        //获取异常中第一个错误信息
        String message = e.getConstraintViolations().iterator().next().getMessage();
        return JsonData.fail(ResponseEnum.PARAM_FAIL.getCode(), message);
    }

    //处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseData MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        this.logger.error(e.getMessage(), e);
        String message = e.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining());
        return JsonData.fail(ResponseEnum.PARAM_FAIL.getCode(), message);
    }

    @ExceptionHandler({UnsupportedOperationException.class})
    public ResponseData UnsupportedOperationExceptionHandler(UnsupportedOperationException e) {
        this.logger.error(e.getMessage(), e);
        return JsonData.fail("请求头中无客户端信息");
    }

    @ExceptionHandler({BusinessException.class})
    public ResponseData BusinessExceptionHandlerHandler(BusinessException e) {
        this.logger.error(e.getMessage(), e);
        return JsonData.fail(e.getCode(), e.getMessage());
    }

}



